package easier.fast.service;

import android.util.Base64;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * 加密工具
 */
public class AESUtil {

    /**
     * 基础参数
     */
    private static final String from = "4C0995744655A0EF16D5B8E6B829EB7F";

    private static final String CipherMode = "AES/CBC/NoPadding";//使用CFB加密，需要设置IV
    private static final String key = f4( from );
    private static final String iv = f5( from.substring( 16 ) );
    private static final String appKey = f6( from );

    private static SecretKeySpec keySpec = new SecretKeySpec( key.getBytes(), "AES" );
    private static IvParameterSpec ivSpec = new IvParameterSpec( iv.getBytes() );

    public static String getAppKey() {

        return appKey;
    }

    private static SecretKeySpec getKeySpec() {

        if ( keySpec != null ) {
            return keySpec;
        } else {
            return keySpec = new SecretKeySpec( key.getBytes(), "AES" );
        }
    }

    private static IvParameterSpec getIvSpec() {

        if ( ivSpec != null ) {
            return ivSpec;
        } else {
            return ivSpec = new IvParameterSpec( iv.getBytes() );
        }
    }

    /**
     * @param data 加密
     *
     * @return 加密后数据
     */
    public static String encrypt( String data ) {

        try {
            Cipher cipher = Cipher.getInstance( CipherMode );
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            if ( plaintextLength % blockSize != 0 ) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy( dataBytes, 0, plaintext, 0, dataBytes.length );
            SecretKeySpec keySpec = getKeySpec();
            IvParameterSpec ivSpec = getIvSpec();
            cipher.init( Cipher.ENCRYPT_MODE, keySpec, ivSpec );
            byte[] encrypted = cipher.doFinal( plaintext );
            return encryptBASE64( encrypted ).trim();

        } catch ( Exception e ) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param data 解密
     *
     * @return 解密后数据
     */
    public static String desEncrypt( String data ) {

        try {
            byte[] encrypted1 = new byte[0];
            encrypted1 = decryptBASE64( data );
            Cipher cipher = Cipher.getInstance( CipherMode );
            SecretKeySpec keySpec = getKeySpec();
            IvParameterSpec ivSpec = getIvSpec();
            cipher.init( Cipher.DECRYPT_MODE, keySpec, ivSpec );
            byte[] original = cipher.doFinal( encrypted1 );
            return new String( original, StandardCharsets.UTF_8 ).trim();
        } catch ( Exception e ) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param data 加密数据
     */
    private static String encryptBASE64( byte[] data ) {
        // BASE64Encoder encoder = new BASE64Encoder();
        // String encode = encoder.encode(data);
        // 从JKD 9开始rt.jar包已废除，从JDK 1.8开始使用java.util.Base64.Encoder
        java.util.Base64.Encoder encoder = null;
        if ( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ) {
            encoder = java.util.Base64.getEncoder();
            return encoder.encodeToString( data );
        } else {
            return Base64.encodeToString( data, Base64.DEFAULT );
        }

    }

    /**
     * BASE64Decoder 解密
     *
     * @param data 要解密的字符串
     *
     * @return 解密后的byte[]
     */
    private static byte[] decryptBASE64( String data ) {
        // BASE64Decoder decoder = new BASE64Decoder();
        // byte[] buffer = decoder.decodeBuffer(data);
        // 从JKD 9开始rt.jar包已废除，从JDK 1.8开始使用java.util.Base64.Decoder
        java.util.Base64.Decoder decoder = null;
        if ( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ) {
            decoder = java.util.Base64.getDecoder();
            return decoder.decode( data );
        } else {
            return Base64.decode( data, Base64.DEFAULT );
        }
    }

    /***************** 以下加密参数 *****************/

    private static String f1( String s ) {

        StringBuilder builder = new StringBuilder( s );
        return builder.reverse().toString();
    }

    private static String f2( String s1, String s2 ) {

        StringBuilder builder = new StringBuilder();

        int length = Math.min( s1.length(), s2.length() );

        for ( int i = 0; i < length; i++ ) {
            builder.append( s1.charAt( i ) );
            builder.append( s2.charAt( i ) );
        }

        String s = s1.length() > s2.length() ? s1 : s2;

        if ( s.length() > length ) {
            builder.append( s.substring( length ) );
        }

        return builder.toString();
    }

    public static String f3( String s, int n ) {

        StringBuilder builder = new StringBuilder();

        for ( int i = 0; i < s.length(); i++ ) {
            int j = i % 3;
            int k = Math.abs( s.charAt( i ) << n );
            if ( j == 0 ) {
                builder.append( (char) (k % 26 + 97) );
            } else if ( j == 1 ) {
                builder.append( (char) (k % 26 + 65) );
            } else {
                builder.append( (char) (k % 10 + 48) );
            }
        }

        return builder.toString();
    }

    /**
     * @param str 数据
     *
     * @return key
     */
    public static String f4( String str ) {

        return f2( str.substring( 0, 4 ) + f1( str.substring( 4, 8 ) ),
            f3( str.substring( 8, 12 ), 1 ) + str.substring( 12, 16 ) );
    }

    /**
     * @param str 数据
     *
     * @return iv
     */
    public static String f5( String str ) {

        return f3(
            f2( str.substring( 0, 4 ), str.substring( 4, 8 ) ) + f1( f2( str.substring( 8, 12 ), str.substring( 12, 16 ) ) ), 2 );
    }

    /**
     * @param str 数据
     *
     * @return appkey
     */
    public static String f6( String str ) {

        return f2( f1( str.substring( 0, 4 ) ) + f3( str.substring( 4, 8 ), 3 ),
            f2( str.substring( 8, 12 ), str.substring( 12, 16 ) ) );
    }
}

